<?php declare(strict_types=1);
/**
 * @author      xianganyall <xianganyall@gmail.com>
 * @copyright   2023-2025 owner
 **/

namespace Srv\Libs\Frame;

use Exception;
use Srv\Apps\Proto\DTO\RequestDTO;
use Srv\Apps\Proto\Enum\ErrCodeEnum;
use Srv\Apps\Proto\Enum\LangKeyEnum;
use Srv\Apps\Proto\Enum\ResultTypeEnum;
use Srv\Apps\Proto\VO\ResponseErrorVO;
use Srv\Apps\Proto\VO\ResponseVO;
use Srv\Libs\Common\CommJson;
use Srv\Libs\Common\CommNet;
use Srv\Libs\Common\CommString;
use Srv\Libs\Common\CommTime;
use Srv\Libs\Common\CommXml;
use Srv\Libs\ConfModel\RouteConf;
use Srv\Libs\ConfModel\RouteConfData;
use Srv\Libs\Tools\Des;
use Srv\Libs\Tools\Http;
use Swoole\Http\Response;
use Swoole\WebSocket\Server;

final class ResponseData
{
    public const RSP_ID                             = 'id';                         // id
    public const RSP_ERR                            = 'error';                      // Error
    public const RSP_ERR_CODE                       = 'code';                       // ErrCode
    public const RSP_ERR_MSG                        = 'message';                    // ErrMessage
    public const RSP_ERR_DATA                       = 'data';                       // ErrData
    public const RSP_RESULT                         = 'result';                     // data
    public const RSP_RESULT_TYPE                    = 'resultType';                 // dataType
    public const RSP_DEBUG                          = 'debug';                      // debug
    public const RSP_XML_ROOT                       = 'xml';                        // xml-root
    public const RSP_XML_ENCODE                     = 'UTF-8';                      // xml-encode
    public const RSP_XML_VERSION                    = '1.0';                        // xml-version
    public const REQ_CONTENT_SECRET_NONE            = 'NONE';                       // 请求Content-不加密
    public const REQ_CONTENT_SECRET_NONCE           = 'NONCE';                      // 请求Content-不加密[旧]
    public const REQ_CONTENT_SECRET_RAND            = 'RAND';                       // 请求Content-随机加密
    public const REQ_CONTENT_SECRET_RAND_AUTO       = 'RAND_AUTO';                  // 请求Content-随机加密-自动识别请求头
    public const NAME_PARAM_TYPE_JSON               = 'JSON';                       // 参数格式JSON
    public const NAME_PARAM_TYPE_XML                = 'XML';                        // 参数格式XML
    public const NAME_PARAM_TYPE_PROTOBUF           = 'PROTOBUF';                   // 参数格式PROTOBUF
    public const NAME_PARAM_TYPE_FROM               = 'FROM';                       // 参数格式FROM
    public const RSP_CONTENT_TYPE_NAME              = 'Content-Type';               // Content-Type
    public const RSP_CONTENT_ENCODE                 = 'utf-8';                      // Content-encode
    public const RSP_CONTENT_SECRET_NONE            = 'NONE';                       // Content-不加密
    public const RSP_CONTENT_SECRET_NONCE           = 'NONCE';                      // Content-不加密[旧]
    public const RSP_CONTENT_SECRET_RAND            = 'RAND';                       // Content-随机加密
    public const RSP_CONTENT_SECRET_RAND_AUTO       = 'RAND_AUTO';                  // Content-随机加密-自动同步请求加密状态
    public const RSP_SMARTY_TPL_NONE                = 'NONE';                       // Smarty模板空Content内容
    public const NAME_CONTENT_TYPE_JSON             = 'JSON';                       // JSON
    public const NAME_CONTENT_TYPE_XML              = 'XML';                        // XML
    public const NAME_CONTENT_TYPE_PROTOBUF         = 'PROTOBUF';                   // PROTOBUF
    public const NAME_CONTENT_TYPE_BINARY           = 'BINARY';                     // BINARY
    public const NAME_CONTENT_TYPE_TEXT             = 'TEXT';                       // TEXT
    public const NAME_CONTENT_TYPE_HTML             = 'HTML';                       // HTML
    public const VAL_CONTENT_TYPE_JSON              = 'application/json';           // JSON
    public const VAL_CONTENT_TYPE_XML               = 'application/xml';            // XML
    public const VAL_CONTENT_TYPE_PROTOBUF          = 'application/protobuf';       // PROTOBUF
    public const VAL_CONTENT_TYPE_TEXT_OR_HTML      = 'text/html';                  // TEXT
    public const VAL_CONTENT_TYPE_BINARY            = 'application/octet-binary';   // BINARY
    private static int $httpCode                    = 200;                          // HTTP代码
    private static int $id                          = 0;                            // 请求Id
    private static int $errCode                     = 0;                            // 错误代码
    private static string $errMsg                   = '';                           // 错误消息
    private static ?RouteConfData $RouteConfData    = null;                         // RouteConfData
    private static ?VOAbstract $errData             = null;                         // 错误响应数据
    private static ?VOAbstract $result              = null;                         // 响应数据
    private static int $resultType                  = 0;                            // 响应数据类别
    private static array $ignoreVOList              = [];                           // 忽略VO字段名
    private static array $debugData                 = [];                           // DEBUG数据
    private static string $customContentType        = '';                           // 自定义HeaderContentType
    private static string $customContentEncode      = '';                           // 自定义HeaderContentEncode
    private static array $customCookie              = [];                           // 自定义Cookie
    private static array $customHeader              = [];                           // 自定义Header
    private static string $customBody               = '';                           // 自定义Body
    private static string $rspContentType           = self::NAME_CONTENT_TYPE_HTML; // 响应Body类型
    private static bool $isSecret                   = false;                        // 响应Body是否加密
    private static bool $isSig                      = false;                        // 响应Body是否签名
    private static string $secretKey                = '';                           // 响应Body加密KEY
    private static string $appSecret                = '';                           // 约定密钥
    private static string $smartyException          = '';                           // smartyException
    private static string $smartyError              = '';                           // smartyError
    private static string $smartyNotFound           = '';                           // smartyNotFound
    private static string $smartyNoPermission       = '';                           // smartyNoPermission
    private static string $smartyParamFail          = '';                           // smartyParamFail

    /**
     * @return void
     * init
     */
    public static function init():void
    {
        self::$httpCode                             = 200;
        self::$id                                   = 0;
        self::$errCode                              = 0;
        self::$errMsg                               = '';
        self::$RouteConfData                        = null;
        self::$errData                              = null;
        self::$result                               = null;
        self::$resultType                           = 0;
        self::$ignoreVOList                         = [];
        self::$debugData                            = [];
        self::$customCookie                         = [];
        self::$customHeader                         = [];
        self::$customBody                           = '';
        self::$rspContentType                       = self::NAME_CONTENT_TYPE_HTML;
        self::$isSecret                             = false;
        self::$isSig                                = false;
        self::$secretKey                            = '';
        self::$appSecret                            = '';
        self::$customContentType                    = '';
        self::$customContentEncode                  = '';
        self::$smartyException                      = '';
        self::$smartyError                          = '';
        self::$smartyNotFound                       = '';
        self::$smartyNoPermission                   = '';
        self::$smartyParamFail                      = '';
    }

    /**
     * @return string
     * getDataJson
     */
    public static function getDataJson():string
    {
        return CommJson::encodeArray([
            self::$httpCode,
            self::$id,
            self::$errCode,
            self::$errMsg,
            self::$errData,
            self::$result,
            self::$resultType,
            self::$ignoreVOList,
            self::$debugData,
            self::$customCookie,
            self::$customHeader,
            self::$customBody,
            self::$rspContentType,
            self::$isSecret,
            self::$isSig,
            self::$secretKey,
            self::$appSecret,
            self::$customContentType,
            self::$customContentEncode,
            self::$smartyException,
            self::$smartyError,
            self::$smartyNotFound,
            self::$smartyNoPermission,
            self::$smartyParamFail,
        ]);
    }

    /**
     * @param string $jsonStr
     * @return bool
     * mergeFromJson
     */
    public static function mergeFromJson(string $jsonStr):bool
    {
        $jsonData                                   = CommJson::decodeArray($jsonStr);
        try{
            self::$httpCode                         = $jsonData[0]??200;
            self::$id                               = $jsonData[1]??0;
            self::$errCode                          = $jsonData[2]??0;
            self::$errMsg                           = $jsonData[3]??'';
            self::$errData                          = $jsonData[4]??null;
            self::$result                           = $jsonData[5]??null;
            self::$resultType                       = $jsonData[6]??0;
            self::$ignoreVOList                     = $jsonData[7]??[];
            self::$debugData                        = $jsonData[8]??[];
            self::$customCookie                     = $jsonData[9]??[];
            self::$customHeader                     = $jsonData[10]??[];
            self::$customBody                       = $jsonData[11]??'';
            self::$rspContentType                   = $jsonData[12]??self::NAME_CONTENT_TYPE_HTML;
            self::$isSecret                         = $jsonData[13]??false;
            self::$isSig                            = $jsonData[14]??false;
            self::$secretKey                        = $jsonData[15]??'';
            self::$appSecret                        = $jsonData[16]??'';
            self::$customContentType                = $jsonData[17]??'';
            self::$customContentEncode              = $jsonData[18]??'';
            self::$smartyException                  = $jsonData[19]??'';
            self::$smartyError                      = $jsonData[20]??'';
            self::$smartyNotFound                   = $jsonData[21]??'';
            self::$smartyNoPermission               = $jsonData[22]??'';
            self::$smartyParamFail                  = $jsonData[23]??'';
            return true;
        }catch(Exception $Exception){
            return false;
        }
    }

    /**
     * @param string $rspContentType
     * @param string $secretType
     * @param bool $isSig
     * @param string $appSecret
     * @param string $smartyException
     * @param string $smartyError
     * @param string $smartyNotFound
     * @param string $smartyNoPermission
     * @param string $smartyParamFail
     * @return void
     * initRspContentHandleType
     */
    public static function initRspContentHandleType(string $rspContentType, string $secretType, bool $isSig, string $appSecret, string $smartyException, string $smartyError, string $smartyNotFound, string $smartyNoPermission, string $smartyParamFail):void
    {
        self::setRspContentSecret($secretType);
        self::setRspContentType($rspContentType);
        self::setRspContentSig($isSig);
        self::$appSecret                    = $appSecret;
        self::$smartyException              = $smartyException;
        self::$smartyError                  = $smartyError;
        self::$smartyNotFound               = $smartyNotFound;
        self::$smartyNoPermission           = $smartyNoPermission;
        self::$smartyParamFail              = $smartyParamFail;
    }

    /**
     * @param bool $isSig
     * @return void
     * setRspContentSig
     */
    public static function setRspContentSig(bool $isSig):void
    {
        self::$isSig                        = $isSig;
    }

    /**
     * @param string $customContentType
     * @return void
     * setContentType
     */
    public static function setContentType(string $customContentType):void
    {
        self::$customContentType            = $customContentType;
    }

    /**
     * @param string $customContentEncode
     * @return void
     * setContentEncode
     */
    public static function setContentEncode(string $customContentEncode):void
    {
        self::$customContentEncode          = $customContentEncode;
    }

    /**
     * @param string $secretType
     * @return void
     * setRspContentSecret
     */
    public static function setRspContentSecret(string $secretType):void
    {
        switch (strtoupper($secretType)){
            case self::RSP_CONTENT_SECRET_NONE:{
                self::$isSecret             = false;
                self::$secretKey            = '';
                break;
            }
            case self::RSP_CONTENT_SECRET_RAND:{
                self::$isSecret             = true;
                self::$secretKey            = CommString::genRandStr(16);   // 兼容APP固定长度16
                break;
            }
            case self::RSP_CONTENT_SECRET_RAND_AUTO:{
                $headerKey                  = EnvData::getDataByHeaderItem(ResponseMain::HEADER_X_KEY);
                if(!is_string($headerKey) || strlen($headerKey) < 1 || $headerKey === ResponseData::REQ_CONTENT_SECRET_NONCE){
                    self::$isSecret         = false;
                    self::$secretKey        = '';
                }else{
                    self::$isSecret         = true;
                    self::$secretKey        = CommString::genRandStr(16);   // 兼容APP固定长度16
                }
                break;
            }
            default:{
                if(strlen($secretType) >= 8){
                    self::$isSecret         = true;
                    self::$secretKey        = $secretType;
                }else{
                    self::$isSecret         = false;
                    self::$secretKey        = '';
                }
            }
        }
    }

    /**
     * @param string $rspContentType
     * @return void
     * setRspContentType
     */
    public static function setRspContentType(string $rspContentType):void
    {
        switch (strtoupper($rspContentType)){
            case self::NAME_CONTENT_TYPE_JSON:{
                self::$rspContentType       = self::NAME_CONTENT_TYPE_JSON;
                break;
            }
            case self::NAME_CONTENT_TYPE_XML:{
                self::$rspContentType       = self::NAME_CONTENT_TYPE_XML;
                break;
            }
            case self::NAME_CONTENT_TYPE_PROTOBUF:{
                self::$rspContentType       = self::NAME_CONTENT_TYPE_PROTOBUF;
                break;
            }
            case self::NAME_CONTENT_TYPE_BINARY:{
                self::$rspContentType       = self::NAME_CONTENT_TYPE_BINARY;
                break;
            }
            case self::NAME_CONTENT_TYPE_TEXT:{
                self::$rspContentType       = self::NAME_CONTENT_TYPE_TEXT;
                break;
            }
            default:{
                self::$rspContentType       = self::NAME_CONTENT_TYPE_HTML;
            }
        }
    }

    /**
     * @return bool
     * rspNoPush
     */
    public static function rspNoPush():bool
    {
        self::$rspContentType       = self::NAME_CONTENT_TYPE_TEXT;
        self::$customBody           = '';
        return true;
    }

    /**
     * @param string $customBody
     * @param VOAbstract|null $result
     * @param array $ignoreVOList
     * @return bool
     * rspSuccAuto
     */
    public static function rspSuccAuto(string $customBody = '', ?VOAbstract $result = null, array $ignoreVOList = []):bool
    {
        self::$errCode              = ErrCodeEnum::ERR_SUCCESS;
        self::$errMsg               = '';
        self::$customBody           = $customBody;
        self::$result               = $result;
        self::$ignoreVOList         = $ignoreVOList;
        return true;
    }

    /**
     * @param string $customBody
     * @return bool
     * rspSuccHtml
     */
    public static function rspSuccHtml(string $customBody):bool
    {
        self::$errCode              = ErrCodeEnum::ERR_SUCCESS;
        self::$errMsg               = '';
        self::$rspContentType       = self::NAME_CONTENT_TYPE_HTML;
        self::$customBody           = $customBody;
        return true;
    }

    /**
     * @param string $customBody
     * @param string $customContentType
     * @return bool
     * rspSuccText
     */
    public static function rspSuccText(string $customBody, string $customContentType = ''):bool
    {
        self::$errCode              = ErrCodeEnum::ERR_SUCCESS;
        self::$errMsg               = '';
        if(strlen($customContentType) > 0) self::setContentType($customContentType);
        self::$rspContentType       = self::NAME_CONTENT_TYPE_TEXT;
        self::$customBody           = $customBody;
        return true;
    }

    /**
     * @param string $customBody
     * @return bool
     * rspSuccBinary
     */
    public static function rspSuccBinary(string $customBody):bool
    {
        self::$errCode              = ErrCodeEnum::ERR_SUCCESS;
        self::$errMsg               = '';
        self::$rspContentType       = self::NAME_CONTENT_TYPE_BINARY;
        self::$customBody           = $customBody;
        return true;
    }

    /**
     * @param VOAbstract|null $result
     * @param array $ignoreVOList
     * @return bool
     * rspSuccJson
     */
    public static function rspSuccJson(?VOAbstract $result = null, array $ignoreVOList = []):bool
    {
        self::$errCode              = ErrCodeEnum::ERR_SUCCESS;
        self::$errMsg               = '';
        self::$rspContentType       = self::NAME_CONTENT_TYPE_JSON;
        self::$result               = $result;
        self::$ignoreVOList         = $ignoreVOList;
        return true;
    }

    /**
     * @param VOAbstract|null $result
     * @param array $ignoreVOList
     * @return bool
     * rspSuccXml
     */
    public static function rspSuccXml(?VOAbstract $result = null, array $ignoreVOList = []):bool
    {
        self::$errCode              = ErrCodeEnum::ERR_SUCCESS;
        self::$errMsg               = '';
        self::$rspContentType       = self::NAME_CONTENT_TYPE_XML;
        self::$result               = $result;
        self::$ignoreVOList         = $ignoreVOList;
        return true;
    }

    /**
     * @param VOAbstract|null $result
     * @param array $ignoreVOList
     * @return bool
     * rspSuccProtobuf
     */
    public static function rspSuccProtobuf(?VOAbstract $result = null, array $ignoreVOList = []):bool
    {
        self::$errCode              = ErrCodeEnum::ERR_SUCCESS;
        self::$errMsg               = '';
        self::$rspContentType       = self::NAME_CONTENT_TYPE_PROTOBUF;
        self::$result               = $result;
        self::$ignoreVOList         = $ignoreVOList;
        return true;
    }

    /**
     * @param int $errCode
     * @param string $errMsg
     * @param VOAbstract|null $errData
     * @param array $ignoreVOList
     * @return bool
     * rspErrAuto
     */
    public static function rspErrAuto(int $errCode, string $errMsg, ?VOAbstract $errData = null, array $ignoreVOList = []):bool
    {
        self::$errCode              = $errCode;
        self::$errMsg               = $errMsg;
        self::$errData              = $errData;
        self::$ignoreVOList         = $ignoreVOList;
        return false;
    }

    /**
     * @param int $errCode
     * @param string $errMsg
     * @param VOAbstract|null $errData
     * @param array $ignoreVOList
     * @return bool
     * rspErrHtml
     */
    public static function rspErrHtml(int $errCode, string $errMsg, ?VOAbstract $errData = null, array $ignoreVOList = []):bool
    {
        self::$rspContentType       = self::NAME_CONTENT_TYPE_HTML;
        self::$errCode              = $errCode;
        self::$errMsg               = $errMsg;
        self::$errData              = $errData;
        self::$ignoreVOList         = $ignoreVOList;
        return false;
    }

    /**
     * @param int $errCode
     * @param string $errMsg
     * @param VOAbstract|null $errData
     * @param array $ignoreVOList
     * @return bool
     * rspErrText
     */
    public static function rspErrText(int $errCode, string $errMsg, ?VOAbstract $errData = null, array $ignoreVOList = []):bool
    {
        self::$rspContentType       = self::NAME_CONTENT_TYPE_TEXT;
        self::$errCode              = $errCode;
        self::$errMsg               = $errMsg;
        self::$errData              = $errData;
        self::$ignoreVOList         = $ignoreVOList;
        return false;
    }

    /**
     * @param int $errCode
     * @param string $errMsg
     * @param VOAbstract|null $errData
     * @param array $ignoreVOList
     * @return bool
     * rspErrBinary
     */
    public static function rspErrBinary(int $errCode, string $errMsg, ?VOAbstract $errData = null, array $ignoreVOList = []):bool
    {
        self::$rspContentType       = self::NAME_CONTENT_TYPE_BINARY;
        self::$errCode              = $errCode;
        self::$errMsg               = $errMsg;
        self::$errData              = $errData;
        self::$ignoreVOList         = $ignoreVOList;
        return false;
    }

    /**
     * @param int $errCode
     * @param string $errMsg
     * @param VOAbstract|null $errData
     * @param array $ignoreVOList
     * @return bool
     * rspErrJson
     */
    public static function rspErrJson(int $errCode, string $errMsg, ?VOAbstract $errData = null, array $ignoreVOList = []):bool
    {
        self::$rspContentType       = self::NAME_CONTENT_TYPE_JSON;
        self::$errCode              = $errCode;
        self::$errMsg               = $errMsg;
        self::$errData              = $errData;
        self::$ignoreVOList         = $ignoreVOList;
        return false;
    }

    /**
     * @param int $errCode
     * @param string $errMsg
     * @param VOAbstract|null $errData
     * @param array $ignoreVOList
     * @return bool
     * rspErrXml
     */
    public static function rspErrXml(int $errCode, string $errMsg, ?VOAbstract $errData = null, array $ignoreVOList = []):bool
    {
        self::$rspContentType       = self::NAME_CONTENT_TYPE_XML;
        self::$errCode              = $errCode;
        self::$errMsg               = $errMsg;
        self::$errData              = $errData;
        self::$ignoreVOList         = $ignoreVOList;
        return false;
    }

    /**
     * @param int $errCode
     * @param string $errMsg
     * @param VOAbstract|null $errData
     * @param array $ignoreVOList
     * @return bool
     * rspErrProtobuf
     */
    public static function rspErrProtobuf(int $errCode, string $errMsg, ?VOAbstract $errData = null, array $ignoreVOList = []):bool
    {
        self::$rspContentType       = self::NAME_CONTENT_TYPE_PROTOBUF;
        self::$errCode              = $errCode;
        self::$errMsg               = $errMsg;
        self::$errData              = $errData;
        self::$ignoreVOList         = $ignoreVOList;
        return false;
    }

    /**
     * @param int $httpCode
     * @return void
     * setHttpCode
     */
    public static function setHttpCode(int $httpCode):void
    {
        self::$httpCode             = $httpCode;
    }

    /**
     * @param int $reqId
     * @return void
     * setReqId
     */
    public static function setReqId(int $reqId):void
    {
        self::$id                   = $reqId;
    }

    /**
     * @param RouteConfData|null $RouteConfData
     * @return void
     * setRouteConfData
     */
    public static function setRouteConfData(?RouteConfData $RouteConfData):void
    {
        self::$RouteConfData        = $RouteConfData;
    }

    /**
     * @return int
     * getReqId
     */
    public static function getReqId():int
    {
        return self::$id;
    }

    /**
     * @param string $cookieName
     * @param string $value
     * @param int $expires
     * @param string $path
     * @param string $domain
     * @param bool $secure
     * @param bool $httponly
     * @return void
     * addCustomCookie
     */
    public static function addCustomCookie(string $cookieName, string $value, int $expires = 0, string $path = '/', string $domain = '', bool $secure = false, bool $httponly = false):void
    {
        self::$customCookie[$cookieName] = ['value' => $value, 'expires' => $expires, 'path' => $path, 'domain' => $domain, 'secure' => $secure, 'httponly' => $httponly];
    }

    /**
     * @param string $headerKey
     * @param string $headerVal
     * @return void
     * addCustomHeader
     */
    public static function addCustomHeader(string $headerKey, string $headerVal):void
    {
        self::$customHeader[$headerKey] = $headerVal;
    }

    /**
     * @param array $customHeader
     * @return void
     * setCustomHeader
     */
    public static function setCustomHeader(array $customHeader):void
    {
        self::$customHeader         = $customHeader;
    }

    /**
     * @param array $debugData
     * @return void
     * setDebugData
     */
    public static function setDebugData(array $debugData):void
    {
        self::$debugData            = $debugData;
    }

    /**
     * @param int $resultType
     * @return void
     * setResultType
     */
    public static function setResultType(int $resultType):void
    {
        self::$resultType           = $resultType;
    }

    /**
     * @param Server $WebSocketServer
     * @param int $fd
     * @param RouteConf|null $RouteConf
     * @param string $urlPath
     * @return void
     * pushEnd
     */
    public static function pushEnd(Server $WebSocketServer, int $fd, ?RouteConf $RouteConf = null, string $urlPath = ''):void
    {
        ResponseMain::stop();
        $isRelease              = ActionAbstract::isRelease();
        switch (self::$rspContentType){
            case self::NAME_CONTENT_TYPE_JSON:{
                $isPushBinary   = self::$isSecret;
                $rspContent     = self::getJsonStr($isRelease);
                break;
            }
            case self::NAME_CONTENT_TYPE_XML:{
                $isPushBinary   = self::$isSecret;
                $rspContent     = self::getXmlStr($isRelease);
                break;
            }
            case self::NAME_CONTENT_TYPE_PROTOBUF:{
                $isPushBinary   = true;
                $rspContent     = self::getProtobufStr($isRelease);
                break;
            }
            case self::NAME_CONTENT_TYPE_BINARY:{
                $isPushBinary   = true;
                $rspContent     = self::$customBody;
                break;
            }
            case self::NAME_CONTENT_TYPE_TEXT:{
                $isPushBinary   = self::$isSecret;
                $rspContent     = self::$customBody;
                break;
            }
            default:{
                $isPushBinary   = self::$isSecret;
                $rspContent     = self::$customBody;
            }
        }
        if(strlen($rspContent) > 0){    // 加密内容
            if(self::$isSecret || strlen(self::$secretKey) > 0) $rspContent = Des::encrypt($rspContent, self::$secretKey, '');
            if($isPushBinary){
                $WebSocketServer->push($fd, $rspContent, WEBSOCKET_OPCODE_BINARY, SWOOLE_WEBSOCKET_FLAG_FIN);
            }else{
                $WebSocketServer->push($fd, $rspContent, WEBSOCKET_OPCODE_TEXT, SWOOLE_WEBSOCKET_FLAG_FIN);
            }
        }
        // 记录运行数据
        if(strlen($urlPath) < 1 || !($RouteConf instanceof RouteConf)) return;
        $runTimeMicro       = self::$debugData[ResponseMain::DEBUG_TIME]??0;
        $runResult          = self::$errCode === 0;
        $isSaveRecord       = $RouteConf->getRecordLevel() === 1;
        if(!$isSaveRecord && $RouteConf->getRecordLevel() === 2 && (!$runResult || ($RouteConf->getRecordSlowTimeMill() > 0 && $RouteConf->getRecordSlowTimeMill()*1000 <= $runTimeMicro))) $isSaveRecord = true;
        // 加载路由配置规则
        if(self::$RouteConfData instanceof RouteConfData){
            $path           = self::$RouteConfData->getUrlPath();
            $FlagList       = self::$RouteConfData->getFlagList();
            if(in_array('REQ_LOG=1', $FlagList, true)){
                $isSaveRecord   = true;
            }else if(in_array('REQ_LOG=0', $FlagList, true)){
                $isSaveRecord   = false;
            }
        }else{
            $path           = $urlPath;
        }
        if(!$isSaveRecord) return;
        $currIpInt          = CommNet::getReqIpInt();
        $currTime           = CommTime::getTimeStamp();
        $userId             = AuthData::getLoginUserId();
        $nonceInt           = AuthData::getLoginTokenNonce();
        $devId              = RequestHeader::getDevId();
        $rawContent         = EnvData::getDataByRawContent();
        $reqBodyJson        = CommJson::isJsonString($rawContent) ? $rawContent : (strlen($rawContent) < 1 ? CommJson::JSON_DEFAULT_EMPTY_STRING : CommJson::encodeArray([ResponseMain::KEY_RAW => $rawContent]));
        $reqHeaderJson      = CommJson::encodeArray(EnvData::getDataByHeader());
        $rspBodyJson        = CommJson::isJsonString($rspContent) ? $rspContent : (strlen($rspContent) < 1 ? CommJson::JSON_DEFAULT_EMPTY_STRING : CommJson::encodeArray([ResponseMain::KEY_RAW => $rspContent]));
        $DbAuto             = ControllerAbstract::getDbAuto();
        $DbAuto->query('INSERT INTO '.$DbAuto->getTableNameAll('adm_request_record').' SET rr_category=2, user_id='.$userId.', rr_nonce='.$nonceInt.', rr_dev_id=\''.$DbAuto->getRealEscapeString($devId).'\', rr_ip='.$currIpInt.', rr_path=\''.$DbAuto->getRealEscapeString($path).'\', rr_req_header=\''.$DbAuto->getRealEscapeString($reqHeaderJson).'\', rr_req_body=\''.$DbAuto->getRealEscapeString($reqBodyJson).'\', rr_rsp_body=\''.$DbAuto->getRealEscapeString($rspBodyJson).'\', rr_result='.($runResult?1:2).', rr_result_time='.$runTimeMicro.', rr_result_size='.strlen($rspBodyJson).', rr_create_time='.$currTime);
    }

    /**
     * @param Response $response
     * @param RouteConf $RouteConf
     * @return void
     * responseEnd
     */
    public static function responseEnd(Response $response, RouteConf $RouteConf):void
    {
        ResponseMain::stop();
        $isRelease                      = ActionAbstract::isRelease();
        $headerKeyList                  = [         // skip header list
            strtolower(self::RSP_CONTENT_TYPE_NAME),
            strtolower(ResponseMain::HEADER_X_SIG),
            strtolower(ResponseMain::HEADER_X_KEY),
            strtolower('Access-Control-Allow-Origin'),
        ];
        $isAccessAllowOrigin            = true;
        $isHandleSmartyTpl              = false;
        switch (self::$rspContentType){
            case self::NAME_CONTENT_TYPE_JSON:{
                $response->header(self::RSP_CONTENT_TYPE_NAME, (strlen(self::$customContentType) > 0 ? self::$customContentType : (self::$isSecret ? self::VAL_CONTENT_TYPE_BINARY : self::VAL_CONTENT_TYPE_JSON)).'; charset='.(strlen(self::$customContentEncode) > 0 ? self::$customContentEncode : self::RSP_CONTENT_ENCODE));
                $rspContent             = self::getJsonStr($isRelease);
                $response->status(self::$httpCode);
                break;
            }
            case self::NAME_CONTENT_TYPE_XML:{
                $response->header(self::RSP_CONTENT_TYPE_NAME, (strlen(self::$customContentType) > 0 ? self::$customContentType : (self::$isSecret ? self::VAL_CONTENT_TYPE_BINARY : self::VAL_CONTENT_TYPE_XML)).'; charset='.(strlen(self::$customContentEncode) > 0 ? self::$customContentEncode : self::RSP_CONTENT_ENCODE));
                $rspContent             = self::getXmlStr($isRelease);
                $response->status(self::$httpCode);
                break;
            }
            case self::NAME_CONTENT_TYPE_PROTOBUF:{
                $response->header(self::RSP_CONTENT_TYPE_NAME, (strlen(self::$customContentType) > 0 ? self::$customContentType : (self::$isSecret ? self::VAL_CONTENT_TYPE_BINARY : self::VAL_CONTENT_TYPE_PROTOBUF)).'; charset='.(strlen(self::$customContentEncode) > 0 ? self::$customContentEncode : self::RSP_CONTENT_ENCODE));
                $rspContent             = self::getProtobufStr($isRelease);
                $response->status(self::$httpCode);
                break;
            }
            case self::NAME_CONTENT_TYPE_BINARY:{
                $isAccessAllowOrigin    = false;
                $isHandleSmartyTpl      = true;
                $response->header(self::RSP_CONTENT_TYPE_NAME, (strlen(self::$customContentType) > 0 ? self::$customContentType : self::VAL_CONTENT_TYPE_BINARY).'; charset='.(strlen(self::$customContentEncode) > 0 ? self::$customContentEncode : self::RSP_CONTENT_ENCODE));
                $rspContent             = self::$customBody;
                break;
            }
            case self::NAME_CONTENT_TYPE_TEXT:{
                $isAccessAllowOrigin    = false;
                $isHandleSmartyTpl      = true;
                $response->header(self::RSP_CONTENT_TYPE_NAME, (strlen(self::$customContentType) > 0 ? self::$customContentType : (self::$isSecret ? self::VAL_CONTENT_TYPE_BINARY : self::VAL_CONTENT_TYPE_TEXT_OR_HTML)).'; charset='.(strlen(self::$customContentEncode) > 0 ? self::$customContentEncode : self::RSP_CONTENT_ENCODE));
                $rspContent             = self::$customBody;
                break;
            }
            default:{
                $isAccessAllowOrigin    = false;
                $isHandleSmartyTpl      = true;
                $response->header(self::RSP_CONTENT_TYPE_NAME, (strlen(self::$customContentType) > 0 ? self::$customContentType : (self::$isSecret ? self::VAL_CONTENT_TYPE_BINARY : self::VAL_CONTENT_TYPE_TEXT_OR_HTML)).'; charset='.(strlen(self::$customContentEncode) > 0 ? self::$customContentEncode : self::RSP_CONTENT_ENCODE));
                $rspContent             = self::$customBody;
                switch (self::$errCode){
                    case ErrCodeEnum::ERR_SYS_PARAMS_EMPTY:
                    case ErrCodeEnum::ERR_SYS_PARAMS_ERROR:
                    case ErrCodeEnum::ERR_SYS_PARAMS_EXCEPTION:
                    case ErrCodeEnum::ERR_SYS_PARAMS_CHECK_AUTO_FAIL:{
                        if(strlen(self::$smartyParamFail) > 0){
                            if(strtoupper(self::$smartyParamFail) === self::RSP_SMARTY_TPL_NONE){
                                $rspContent         = '';
                            }else if(self::isSmartyTplFilePath(self::$smartyNoPermission)){
                                $Smarty             = ActionAbstract::getNewSmarty();
                                $Smarty->assign('ERR_DATA', self::$errData ? self::$errData->getDataJsonArray([], true):[]);
                                $Smarty->assign('PARAM_CODE', self::$errCode);
                                if(self::$errCode === ErrCodeEnum::ERR_SYS_PARAMS_EMPTY){
                                    $Smarty->assign('PARAM_MSG', Lang::get(LangKeyEnum::LANG_SYS_PARAMS_EMPTY));
                                }else if(self::$errCode === ErrCodeEnum::ERR_SYS_PARAMS_CHECK_AUTO_FAIL){
                                    $Smarty->assign('PARAM_MSG', Lang::get(LangKeyEnum::LANG_SYS_PARAMS_CHECK_AUTO_FAIL));
                                }else{
                                    $Smarty->assign('PARAM_MSG', Lang::get(LangKeyEnum::LANG_SYS_PARAMS_ERROR));
                                }
                                try{ $rspContent    = strval($Smarty->fetch(self::$smartyParamFail)); }catch(Exception $SmartyException){ $rspContent = ''; }
                            }else{
                                $rspContent         = self::$smartyParamFail;
                            }
                        }
                        break;
                    }
                }
            }
        }
        // 每次响应必须有[允许任意跨域]
        if($isAccessAllowOrigin) $response->header('Access-Control-Allow-Origin', '*');
        // 处理Smarty模板 Exception->Error->NotFound->Auth->Success
        if($isHandleSmartyTpl){
            if(count(self::$debugData[ResponseMain::KEY_EXCEPTION]??[]) > 0){
                if(strlen(self::$smartyException) > 0){
                    if(strtoupper(self::$smartyException) === self::RSP_SMARTY_TPL_NONE){
                        $rspContent         = '';
                    }else if(self::isSmartyTplFilePath(self::$smartyException)){
                        $Smarty             = ActionAbstract::getNewSmarty();
                        $Smarty->assign('EXCEPTION', self::$debugData[ResponseMain::KEY_EXCEPTION]);
                        try{ $rspContent    = strval($Smarty->fetch(self::$smartyException)); }catch(Exception $SmartyException){ $rspContent = ''; }
                    }else{
                        $rspContent         = self::$smartyException;
                    }
                    $response->status(200);
                }else{
                    $response->status(503, 'Service Unavailable');
                }
            }else if(count(self::$debugData[ResponseMain::KEY_ERROR]??[]) > 0){
                if(strlen(self::$smartyError) > 0){
                    if(strtoupper(self::$smartyError) === self::RSP_SMARTY_TPL_NONE){
                        $rspContent         = '';
                    }else if(self::isSmartyTplFilePath(self::$smartyError)){
                        $Smarty             = ActionAbstract::getNewSmarty();
                        $Smarty->assign('ERROR', self::$debugData[ResponseMain::KEY_ERROR]);
                        try{ $rspContent    = strval($Smarty->fetch(self::$smartyError)); }catch(Exception $SmartyException){ $rspContent = ''; }
                    }else{
                        $rspContent         = self::$smartyError;
                    }
                    $response->status(200);
                }else{
                    $response->status(503, 'Service Unavailable');
                }
            }else if(count(self::$debugData[ResponseMain::KEY_NOT_FOUND_REQUEST]??[]) > 0){
                if(strlen(self::$smartyNotFound) > 0){
                    if(strtoupper(self::$smartyNotFound) === self::RSP_SMARTY_TPL_NONE){
                        $rspContent         = '';
                    }else if(self::isSmartyTplFilePath(self::$smartyNotFound)){
                        $Smarty             = ActionAbstract::getNewSmarty();
                        $Smarty->assign('NOT_FOUND', self::$debugData[ResponseMain::KEY_NOT_FOUND_REQUEST]);
                        try{ $rspContent    = strval($Smarty->fetch(self::$smartyNotFound)); }catch(Exception $SmartyException){ $rspContent = ''; }
                    }else{
                        $rspContent         = self::$smartyNotFound;
                    }
                    $response->status(200);
                }else{
                    $response->status(404, 'Not Found');
                }
            }else if(count(self::$debugData[ResponseMain::KEY_AUTH]??[]) > 0){
                if(strlen(self::$smartyNoPermission) > 0){
                    if(strtoupper(self::$smartyNoPermission) === self::RSP_SMARTY_TPL_NONE){
                        $rspContent         = '';
                    }else if(self::isSmartyTplFilePath(self::$smartyNoPermission)){
                        $Smarty             = ActionAbstract::getNewSmarty();
                        $Smarty->assign('NO_PERMISSION', self::$debugData[ResponseMain::KEY_AUTH]);
                        try{ $rspContent    = strval($Smarty->fetch(self::$smartyNoPermission)); }catch(Exception $SmartyException){ $rspContent = ''; }
                    }else{
                        $rspContent         = self::$smartyNoPermission;
                    }
                    $response->status(200);
                }else{
                    $response->status(401, 'Unauthorized');
                }
            }else{
                $response->status(self::$httpCode);
            }
        }
        $rspContentResult           = $rspContent;
        // 允许Web获取响应header的Key列表
        $rspExposeHeaderList        = [];
        // 加密内容
        if(self::$isSecret){
            $isSet                  = false;
            $headerXAppNonce        = Http::getXAppNonce($isSet);
            $rspContentKey          = Des::encrypt(self::$secretKey.$headerXAppNonce, self::$appSecret, Des::DES_OUTPUT_BASE64);
            $rspContentResult       = Des::encrypt($rspContent, self::$secretKey, '');
            $rspContentSha1         = strlen($rspContentResult) > 0 ? sha1(base64_encode($rspContentResult)) : '';
            $response->header(ResponseMain::HEADER_X_KEY, $rspContentKey);
            $rspExposeHeaderList[]  = ResponseMain::HEADER_X_KEY;
        }else{
            $rspContentSha1         = $rspContent;
            if(self::$isSig){
                $response->header(ResponseMain::HEADER_X_KEY, self::RSP_CONTENT_SECRET_NONCE);
                $rspExposeHeaderList[] = ResponseMain::HEADER_X_KEY;
            }
        }
        // 签名内容
        if(self::$isSig){
            $randNonceSha1          = sha1(CommString::genRandStr(mt_rand(12, 16)));
            $isSet                  = false;
            $headerXAppNonce        = Http::getXAppNonce($isSet);
            $headerXDevTime         = Http::getXDevTime($isSet);
            $headerXSig             = Http::getXSig($isSet);
            $rspContentSig          = $randNonceSha1.sha1($randNonceSha1.';'.$headerXSig.';'.sha1(self::$isSecret?self::$secretKey:self::$appSecret).';'.$headerXAppNonce.';'.$headerXDevTime.';'.$rspContentSha1);
            $response->header(ResponseMain::HEADER_X_SIG, $rspContentSig);
            $rspExposeHeaderList[]  = ResponseMain::HEADER_X_SIG;
        }
        if(count($rspExposeHeaderList) > 0) $response->header('Access-Control-Expose-Headers', implode(',', array_merge([ResponseMain::HEADER_CONTENT_TYPE], $rspExposeHeaderList)));
        // 自定义Cookie
        if(count(self::$customCookie) > 0) foreach(self::$customCookie as $cookieName => $cookieData){
            $response->cookie($cookieName, $cookieData['value']??null, $cookieData['expires']??null, $cookieData['path']??null, $cookieData['domain']??null, $cookieData['secure']??null, $cookieData['httponly']??null);
        }
        // 自定义Header
        if(count(self::$customHeader) > 0) foreach(self::$customHeader as $headerKey => $headerVal){
            if(is_string($headerKey) && strlen($headerKey) > 0){
                if(!in_array(strtolower($headerKey), $headerKeyList, true)) $response->header($headerKey, strval($headerVal));
            }
        }
        // 将输出回显到控制台
        if(isset(self::$debugData[ResponseMain::DEBUG_PRINT]) && is_string(self::$debugData[ResponseMain::DEBUG_PRINT]) && strlen(self::$debugData[ResponseMain::DEBUG_PRINT]) > 0) echo self::$debugData[ResponseMain::DEBUG_PRINT];
        $response->end($rspContentResult);
        // 记录运行数据
        $runTimeMicro       = self::$debugData[ResponseMain::DEBUG_TIME]??0;
        $runResult          = self::$errCode === 0;
        $isSaveRecord       = $RouteConf->getRecordLevel() === 1;
        if(!$isSaveRecord && $RouteConf->getRecordLevel() === 2 && (!$runResult || ($RouteConf->getRecordSlowTimeMill() > 0 && $RouteConf->getRecordSlowTimeMill()*1000 <= $runTimeMicro))) $isSaveRecord = true;
        // 加载路由配置规则
        if(self::$RouteConfData instanceof RouteConfData){
            $path           = self::$RouteConfData->getUrlPath();
            $FlagList       = self::$RouteConfData->getFlagList();
            if(in_array('REQ_LOG=1', $FlagList, true)){
                $isSaveRecord   = true;
            }else if(in_array('REQ_LOG=0', $FlagList, true)){
                $isSaveRecord   = false;
            }
        }else{
            $path           = Route::getUrlPath();
        }
        if(!$isSaveRecord) return;
        $currIpInt          = CommNet::getReqIpInt();
        $currTime           = CommTime::getTimeStamp();
        $userId             = AuthData::getLoginUserId();
        $nonceInt           = AuthData::getLoginTokenNonce();
        $devId              = RequestHeader::getDevId();
        $rawContent         = EnvData::getDataByRawContent();
        $reqBodyJson        = CommJson::isJsonString($rawContent) ? $rawContent : (strlen($rawContent) < 1 ? CommJson::JSON_DEFAULT_EMPTY_STRING : CommJson::encodeArray([ResponseMain::KEY_RAW => $rawContent]));
        $reqHeaderJson      = CommJson::encodeArray(EnvData::getDataByHeader());
        $rspBodyJson        = CommJson::isJsonString($rspContent) ? $rspContent : (strlen($rspContent) < 1 ? CommJson::JSON_DEFAULT_EMPTY_STRING : CommJson::encodeArray([ResponseMain::KEY_RAW => $rspContent]));
        $DbAuto             = ControllerAbstract::getDbAuto();
        $DbAuto->query('INSERT INTO '.$DbAuto->getTableNameAll('adm_request_record').' SET rr_category=1, user_id='.$userId.', rr_nonce='.$nonceInt.', rr_dev_id=\''.$DbAuto->getRealEscapeString($devId).'\', rr_ip='.$currIpInt.', rr_path=\''.$DbAuto->getRealEscapeString($path).'\', rr_req_header=\''.$DbAuto->getRealEscapeString($reqHeaderJson).'\', rr_req_body=\''.$DbAuto->getRealEscapeString($reqBodyJson).'\', rr_rsp_body=\''.$DbAuto->getRealEscapeString($rspBodyJson).'\', rr_result='.($runResult?1:2).', rr_result_time='.$runTimeMicro.', rr_result_size='.strlen($rspBodyJson).', rr_create_time='.$currTime);
    }

    /**
     * @param bool $isRelease
     * @return int[]
     * getRspArray
     */
    private static function getRspArray(bool $isRelease):array
    {
        $rspData                        = [self::RSP_ID => self::$id];
        if(self::$resultType > 0) $rspData[self::RSP_RESULT_TYPE] = self::$resultType;
        if(self::$errCode === 0){
            $rspData[self::RSP_RESULT]  = is_null(self::$result) ? [] : self::$result->getDataJsonArray(self::$ignoreVOList, true);
        }else{
            $rspData[self::RSP_ERR]     = [
                self::RSP_ERR_CODE      => self::$errCode,
                self::RSP_ERR_MSG       => self::$errMsg,
                self::RSP_ERR_DATA      => is_null(self::$errData) ? [] : self::$errData->getDataJsonArray(self::$ignoreVOList, true),
            ];
        }
        if(!$isRelease && count(self::$debugData) > 0) $rspData[self::RSP_DEBUG] = self::$debugData;
        return $rspData;
    }

    /**
     * @param bool $isRelease
     * @return string
     * getJsonStr
     */
    private static function getJsonStr(bool $isRelease):string
    {
        return preg_replace("/:\s*\[]/", ': null', CommJson::encodeArray(self::getRspArray($isRelease))); // replace to null
    }

    /**
     * @param bool $isRelease
     * @return string
     * getXmlStr
     */
    private static function getXmlStr(bool $isRelease):string
    {
        return CommXml::arrayToXml(self::getRspArray($isRelease), self::RSP_XML_ROOT, self::RSP_XML_ENCODE, self::RSP_XML_VERSION, CommXml::XML_DEFAULT_SPLIT, true);
    }

    /**
     * @param bool $isRelease
     * @return string
     * getProtobufStr
     */
    private static function getProtobufStr(bool $isRelease):string
    {
        $ResponseVO             = new ResponseVO();
        $ResponseVO->setId(self::$id);
        if(self::$resultType > 0 && ResultTypeEnum::valueExists(self::$resultType)) $ResponseVO->setResultType(self::$resultType);
        if(self::$errCode === 0){
            if(self::$result instanceof VOAbstract) $ResponseVO->setResult(self::$result->toAnyMessage());
        }else{
            $ResponseErrorVO    = new ResponseErrorVO();
            $ResponseErrorVO->setCode(self::$errCode);
            $ResponseErrorVO->setMessage(self::$errMsg);
            if(self::$errData instanceof VOAbstract) $ResponseErrorVO->setData(self::$errData->toAnyMessage());
            $ResponseVO->setError($ResponseErrorVO);
        }
        if(!$isRelease && count(self::$debugData) > 0) $ResponseVO->setDebugJson(preg_replace("/:\s*\[]/", ': null', CommJson::encodeArray(self::$debugData)));
        return $ResponseVO->serializeToString();
    }

    /**
     * @param string $smartyTplFilePath
     * @return bool
     * isSmartyTplFilePath
     */
    public static function isSmartyTplFilePath(string $smartyTplFilePath):bool
    {
        return strtoupper(substr($smartyTplFilePath, -5)) === '.HTML';
    }

    /**
     * @param string $secretType
     * @param string $reqContentSrc
     * @param string $reqContent
     * @param RouteConf $RouteConf
     * @return bool
     * decryptReqContent
     */
    public static function decryptReqContent(string $secretType, string $reqContentSrc, string &$reqContent, RouteConf $RouteConf):bool
    {
        $reqContentSrcLength    = strlen($reqContentSrc);
        if($reqContentSrcLength < 1){
            $reqContent         = '';
            return true;
        }
        switch (strtoupper($secretType)){
            case self::REQ_CONTENT_SECRET_NONE:{
                $reqContent                 = $reqContentSrc;
                return true;
            }
            case self::REQ_CONTENT_SECRET_RAND:{
                $reqContent                 = '';
                $headerKey                  = EnvData::getByHeaderRouteItem(ResponseMain::HEADER_X_KEY, $RouteConf);
                if(!is_string($headerKey) || strlen($headerKey) < 1) return false;
                $secretKey                  = Des::decrypt($headerKey, self::$appSecret, Des::DES_OUTPUT_BASE64);
                if(strlen($secretKey) < 1) return false;
                $reqContent                 = Des::decrypt($reqContentSrc, $secretKey, '');
                if(strlen($reqContent) > 0){
                    EnvData::setDataByRawContent($reqContent);
                    return true;
                }else{
                    return false;
                }
            }
            case self::REQ_CONTENT_SECRET_RAND_AUTO:{
                $reqContent                 = '';
                $headerKey                  = EnvData::getByHeaderRouteItem(ResponseMain::HEADER_X_KEY, $RouteConf);
                if(!is_string($headerKey) || strlen($headerKey) < 1 || $headerKey === ResponseData::REQ_CONTENT_SECRET_NONCE){
                    $reqContent             = $reqContentSrc;
                    return true;
                }else{
                    $secretKey              = Des::decrypt($headerKey, self::$appSecret, Des::DES_OUTPUT_BASE64);
                    if(strlen($secretKey) < 1) return false;
                    $reqContent             = Des::decrypt($reqContentSrc, $secretKey, '');
                    if(strlen($reqContent) > 0){
                        EnvData::setDataByRawContent($reqContent);
                        return true;
                    }else{
                        return false;
                    }
                }
            }
            default:{
                if(strlen($secretType) > 0){
                    $reqContent             = Des::decrypt($reqContentSrc, $secretType, '');
                    if(strlen($reqContent) > 0){
                        EnvData::setDataByRawContent($reqContent);
                        return true;
                    }else{
                        return false;
                    }
                }else{
                    $reqContent             = $reqContentSrc;
                    return true;
                }
            }
        }
    }

    /**
     * @param string $reqContentType
     * @param string $reqContent
     * @param int $reqId
     * @param string $urlPath
     * @param $params
     * @param bool $isCheckType
     * @return bool
     * decodeReqContentSocks
     */
    public static function decodeReqContentSocks(string $reqContentType, string $reqContent, int &$reqId, string &$urlPath, &$params, bool &$isCheckType):bool
    {
        switch (strtoupper($reqContentType)){
            case self::NAME_PARAM_TYPE_JSON:{
                $reqData        = CommJson::decodeArray($reqContent);
                if(!isset($reqData['id']) || !is_numeric($reqData['id'])) return false;
                $reqId          = intval($reqData['id']);
                if(!isset($reqData['method']) || !is_string($reqData['method'])) return false;
                $urlPath        = trim($reqData['method']);
                $params         = $reqData['params']??null;
                $isCheckType    = true;
                return true;
            }
            case self::NAME_PARAM_TYPE_XML:{
                $reqData        = CommXml::xmlToArray($reqContent);
                if(!isset($reqData['id']) || !is_numeric($reqData['id'])) return false;
                $reqId          = intval($reqData['id']);
                if(!isset($reqData['method']) || !is_string($reqData['method'])) return false;
                $urlPath        = trim($reqData['method']);
                $params         = $reqData['params']??null;
                $isCheckType    = true;
                return true;
            }
            case self::NAME_PARAM_TYPE_PROTOBUF:{
                $RequestDTO     = new RequestDTO();
                if(!$RequestDTO->mergeFromStrTry($reqContent)) return false;
                $reqId          = intval($RequestDTO->getId());
                $urlPath        = trim($RequestDTO->getMethod());
                $params         = $RequestDTO->getParams(); // Any
                $isCheckType    = true;
            }
        }
        return true;
    }

    /**
     * @param string $reqContentType
     * @param string $reqContent
     * @param $params
     * @param bool $isCheckType
     * @return bool
     * decodeReqContentWebs
     */
    public static function decodeReqContentWebs(string $reqContentType, string $reqContent, &$params, bool &$isCheckType):bool
    {
        switch (strtoupper($reqContentType)){
            case self::NAME_PARAM_TYPE_JSON:{
                $params         = CommJson::decodeArray($reqContent);
                $isCheckType    = true;
                return true;
            }
            case self::NAME_PARAM_TYPE_XML:{
                $params         = CommXml::xmlToArray($reqContent);
                $isCheckType    = true;
                return true;
            }
            case self::NAME_PARAM_TYPE_PROTOBUF:{
                $params         = $reqContent;
                $isCheckType    = true;
                return true;
            }
            case self::NAME_PARAM_TYPE_FROM:{
                $params         = [];
                $paramList      = array_merge(EnvData::getDataByGet(), EnvData::getDataByPost());
                $actionName     = Conf::getResponseConf()->getActionName();
                if(count($paramList) > 0) foreach ($paramList as $paramKey => $paramVal){
                    if(is_string($paramVal) && ($paramKey === $actionName || strlen($paramVal) < 1)) continue;
                    $params[$paramKey] = $paramVal;
                }
                $isCheckType    = false;
                return true;
            }
        }
        return true;
    }

    /**
     * @param int $fd
     * @param int $time
     * @param string $userId
     * @param string $envStr
     * @param string $groupName
     * @param string $loginKey
     * @param int $loginExpTime
     * @param string $loginPlatform
     * @param string $loginDevId
     * @param string $loginAuth
     * @param string $langType
     * @return void
     * wsOpen
     */
    public static function wsOpen(int $fd, int $time, string $userId, string $envStr, string $groupName, string $loginKey, int $loginExpTime, string $loginPlatform, string $loginDevId, string $loginAuth, string $langType):void
    {
        unset($fd, $time, $userId, $envStr, $groupName, $loginKey, $loginExpTime, $loginPlatform, $loginDevId, $loginAuth, $langType);
    }

    /**
     * @param int $fd
     * @param int $time
     * @param string $userId
     * @param string $envStr
     * @param string $groupName
     * @param string $loginKey
     * @param int $loginExpTime
     * @param string $loginPlatform
     * @param string $loginDevId
     * @param string $loginAuth
     * @param string $langType
     * @return void
     * wsClose
     */
    public static function wsClose(int $fd, int $time, string $userId, string $envStr, string $groupName, string $loginKey, int $loginExpTime, string $loginPlatform, string $loginDevId, string $loginAuth, string $langType):void
    {
        unset($fd, $time, $userId, $envStr, $groupName, $loginKey, $loginExpTime, $loginPlatform, $loginDevId, $loginAuth, $langType);
    }
}